#!/usr/bin/env jruby
# -*- coding: us-ascii -*-
# Elizabeth Wiethoff 2008

require 'java'
require 'pp' if $DEBUG
require 'singleton'

dir = File.dirname(__FILE__)
require File.join(dir, '..', 'src', 'lib', 'auxil', 'javainclude')
require File.join(dir, '..', 'src', 'lib', 'monkey', 'time')

########################################

include_classes 'java.awt', %w[
  BorderLayout Color Dimension FlowLayout GridLayout]

include_classes 'javax.swing', %w[
  BorderFactory Box ButtonGroup
  JButton JFrame JLabel JPanel JRadioButton JScrollPane JTable]

include_classes 'javax.swing.table', %w[
  DefaultTableCellRenderer DefaultTableModel]

include_classes 'java.util', %w[Collections Vector]

%w[
  java.text.DecimalFormat
].each { |klass| include_class klass }

########################################

class FileGroupTCRenderer < DefaultTableCellRenderer
  include Singleton
  
  FORTRAN_GREEN1 = Color.new(0.25, 0.75, 0.25, 0.25)
  FORTRAN_GREEN2 = Color.new(200, 235, 200)
  GREEN_COLOR = FORTRAN_GREEN2
  WHITE_COLOR = Color::WHITE
  
  def initialize
    super
    specializeInitialization  # template method pattern
  end
  
  def getTableCellRendererComponent(table, obj, isSel, foc, row, col)
    super(table, obj, isSel, foc, row, col)
    if isSel
      setForeground(table.getForeground)
      setBackground(table.getSelectionBackground)
    else
      gno = table.getModel.getValueAt(row, 0)  # I don't like this 0
      setBackground((gno % 2).zero? ? WHITE_COLOR : GREEN_COLOR)
    end
    specializeObjectRendering(obj)  # template method pattern
    return self
  end
  
  protected
  def specializeInitialization ; end  # subclasses override
  def specializeObjectRendering(obj) ; end  # subclasses override
end

########################################

class FixnumTCRenderer < FileGroupTCRenderer
  @@formatter = DecimalFormat.getIntegerInstance
  
  private
  
  def specializeInitialization
    setHorizontalAlignment(JLabel::RIGHT)
  end
  
  def specializeObjectRendering(integer)
    setText(@@formatter.format(integer))
  end
end

BignumTCRenderer = FixnumTCRenderer  # alias

########################################

class StringTCRenderer < FileGroupTCRenderer
  private
  def specializeObjectRendering(string)
    setToolTipText(string)
  end
end

########################################

class TimeTCRenderer < FileGroupTCRenderer
  private
  
  def specializeInitialization
    setHorizontalAlignment(JLabel::CENTER)
  end
  
  def specializeObjectRendering(time)
    setText(time.to_s)  # monkey-patched format
  end
end

########################################

class FileGroupTable < JTable
  def getCellRenderer(row, column)
    # use convertColumnIndexToModel so that columns still 
    # render correctly after user moves them
    columnInModel = convertColumnIndexToModel(column)
    obj = getModel.getValueAt(0, columnInModel)
    return Module.const_get("#{obj.class}TCRenderer").instance
  end
end

########################################

class FileGroupTableModel < DefaultTableModel
  include java.awt.event.ActionListener
  
  class SpiffyComparator
    include java.util.Comparator
    
    def initialize(column, meth=:<=>, mult=1)
      @column = column
      @meth = meth
      @mult = mult
    end
    attr_reader :column
    protected :column
    
    def compare(a, b)
      a.elementAt(@column).send(@meth, b.elementAt(@column)) * @mult
    end
    
    def equals(other)
      @column = other.column and 
      @meth = other.meth and 
      @mult = other.mult
    end
  end
  
  GNO_COMPARATOR = SpiffyComparator.new 0
  DIRECTORY_COMPARATOR = SpiffyComparator.new 1, :casecmp
  FILENAME_COMPARATOR = SpiffyComparator.new 2, :casecmp
  MODTIME_COMPARATOR = SpiffyComparator.new 3
  FILESIZE_COMPARATOR = SpiffyComparator.new 4
  GSZ_COMPARATOR = SpiffyComparator.new 5
  
  GNO_REVERSE_COMPARATOR = SpiffyComparator.new 0, :<=>, -1
  DIRECTORY_REVERSE_COMPARATOR = SpiffyComparator.new 1, :casecmp, -1
  FILENAME_REVERSE_COMPARATOR = SpiffyComparator.new 2, :casecmp, -1
  MODTIME_REVERSE_COMPARATOR = SpiffyComparator.new 3, :<=>, -1
  FILESIZE_REVERSE_COMPARATOR = SpiffyComparator.new 4, :<=>, -1
  GSZ_REVERSE_COMPARATOR = SpiffyComparator.new 5, :<=>, -1
  
  def actionPerformed(e)
    command = e.getActionCommand
    comparator = if command =~ /^reverse /i
      cmd = command.split.last
      self.class.const_get "#{cmd}_REVERSE_COMPARATOR".upcase!
    else
      self.class.const_get "#{command}_COMPARATOR".upcase!
    end
    Collections.sort(getDataVector, comparator)
    fireTableRowsUpdated(0, getRowCount-1)
  end
end

########################################

columns = [
  Hash[:title, 'GNo',       :width,  25, :column, 0], 
  Hash[:title, 'Directory', :width, 175, :column, 1], 
  Hash[:title, 'FileName',  :width, 175, :column, 2], 
  Hash[:title, 'ModTime',   :width, 150, :column, 3], 
  Hash[:title, 'FileSize',  :width, 100, :column, 4], 
  Hash[:title, 'GSz',       :width,  25, :column, 5], 
]

data = [
  [1, '/Work',     'foo.txt',    '2007-12-20', 12345, 2], 
  [1, '/Projects', 'foobar.txt', '2007-05-13', 54321, 2], 
  [2, '/Projects', 'barbaz.txt', '2007-10-30',   987, 2], 
  [2, '/Work',     'bar.txt',    '2008-01-24',   654, 2], 
]

f = File.join(dir, '..', 'src', 'test', 'gui', 'projects.tablepp.txt')
begin
data = eval(File.open(f) { |f| f.read })
rescue ; end

require 'time'
data.each { |row| row[3] = Time.parse row[3] }

########################################

pRadios = JPanel.new(GridLayout.new(2, columns.size))
pRadios.setBorder(BorderFactory.createTitledBorder('Sort by'))

buttonGroup = ButtonGroup.new

columns.each do |hash|
  radio = (hash[:title] == 'GNo') ?
    JRadioButton.new(hash[:title], true) : 
    JRadioButton.new(hash[:title])
  pRadios.add(radio)
  buttonGroup.add(radio)
end

columns.each do |hash|
  radio = JRadioButton.new('reverse ' + hash[:title])
  pRadios.add(radio)
  buttonGroup.add(radio)
end

########################################

tableModel = FileGroupTableModel.new
tableModel.setColumnIdentifiers(Vector.new(
  columns.map { |hash| hash[:title] }) )
data.each { |row| tableModel.addRow(Vector.new(row)) }

buttonGroup.getElements.each do |radio|
  radio.addActionListener(tableModel)
end

table = FileGroupTable.new(tableModel)

columnModel = table.getColumnModel
columns.each do |hash|
  column = columnModel.getColumn(hash[:column])
  column.setPreferredWidth(hash[:width])
  column.setMinWidth(hash[:width])
  column.setMaxWidth(hash[:width] * 4) if hash[:title] =~ /^G\w\w$/i
  column.setMaxWidth(hash[:width] * 1.2) if hash[:title] =~ /Time$/i
  column.setMaxWidth(hash[:width] * 1.5) if hash[:title] =~ /^File\s?Size/i
end

########################################

spTable = JScrollPane.new(table)
spTable.setPreferredSize(Dimension.new(800, 400))

########################################

mainFrame = JFrame.new('SuperElse Output Layout')
mainFrame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)

mainContentPane = mainFrame.getContentPane()
mainContentPane.setLayout(BorderLayout.new)
mainContentPane.add(spTable, BorderLayout::CENTER)
mainContentPane.add(pRadios, BorderLayout::SOUTH)

mainFrame.pack()
mainFrame.setVisible(true)
